package com.sql.compare.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.sql.compare.entity.Column;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 比较两个SQL，是否存在表变化和字段变化
 */
public class SqlFileCompareUtils {

    /**
     * 比较多个表字段信息
     *
     * @author xuepeng
     * @date 2024/1/31 11:14
     */
    public static String getDifferenceList(Map<String, List<Column>> fromMap, Map<String, List<Column>> toMap) {
        List<String> list = new ArrayList<String>();
        Set<String> toTableSet = toMap.keySet();
        Set<String> componentInsert = new HashSet<>();
        Set<String> componentUpdate = new HashSet<>();
        for (String tableName : toTableSet) {
            List<Column> fromFieldMap = fromMap.get(tableName);
            //如果目标文件有该表，源文件没有该表，则表已被删除，冗余
            if (CollectionUtil.isEmpty(fromFieldMap)) {
                componentInsert.add(tableName);
                continue;
            }
            // 继续比较表的字段
            List<Column> toFieldMap = toMap.get(tableName);
            List<String> fieldList = getDifferenceFieldList(tableName, fromFieldMap, toFieldMap);
            if (!fieldList.isEmpty()) {
                componentUpdate.add(tableName);
                list.addAll(fieldList);
            }
        }
        StringBuffer sb = new StringBuffer();
        sb.append("-------------------------目标库独有表-----------------------\n");
        for (String tableName : componentInsert) {
            sb.append(tableName).append("\n");
        }
        sb.append("-------------------------源库独有表-------------------------\n");
        Set<String> fromTableSet = fromMap.keySet();
        fromTableSet.removeAll(toTableSet);
        for (String tableName : fromTableSet) {
            sb.append(tableName).append("\n");
        }
        sb.append("-------------------------需要修改表-------------------------\n");
        for (String tableName : componentUpdate) {
            sb.append(tableName).append("\n");
        }
        if (CollectionUtil.isEmpty(list)){
            sb.append("数据库表结构一致！");
            return sb.toString();
        }
        sb.append("-------------------------共变化 " + list.size() + "处，具体如下-------------------------").append("\n");
        for (int i = 0; i < list.size(); i++) {
            sb.append(String.format("【%s】%s", (i + 1), list.get(i))).append("\n");
        }
        return sb.toString();
    }


    /**
     * 比较多个表索引信息
     *
     * @author xuepeng
     * @date 2024/1/30 15:14
     */
    public static String getDifferenceIndexList(Map<String, List<Column>> fromMap, Map<String, List<Column>> toMap) {
        List<String> list = new ArrayList<>();
        Set<String> toTableSet = toMap.keySet();
        Set<String> componentInsert = new HashSet<>();
        Set<String> componentUpdate = new HashSet<>();
        for (String tableName : toTableSet) {
            List<Column> fromKeyMap = fromMap.get(tableName);
            List<Column> toKeyMap = toMap.get(tableName);
            //目标表和源表都为空，说明都没有索引
            if (CollectionUtil.isEmpty(fromKeyMap) && CollectionUtil.isEmpty(toKeyMap)) {
                continue;
            }
            if (CollectionUtil.isEmpty(fromKeyMap) && !CollectionUtil.isEmpty(toKeyMap)) {
                componentInsert.add(tableName);
                continue;
            }
            // 继续比较索引的字段
            List<String> keyList = getDifferenceIndexList(tableName, fromKeyMap, toKeyMap);
            if (!keyList.isEmpty()) {
                componentUpdate.add(tableName);
                list.addAll(keyList);
            }
        }
        StringBuffer sb = new StringBuffer();
        sb.append("-------------------------独有索引目标表-----------------------------\n");
        componentInsert.forEach(temp -> sb.append(temp).append("\n"));
        sb.append("--------------------------独有索引源表------------------------------\n");
        Set<String> fromTableSet = fromMap.keySet();
        fromTableSet.removeAll(toTableSet);
        for (String tableName : fromTableSet) {
            if (CollectionUtil.isNotEmpty(fromMap.get(tableName))) {
                sb.append(tableName).append("\n");
            }
        }
        sb.append("--------------------------需要修改表-------------------------------\n");
        componentUpdate.forEach(temp -> sb.append(temp).append("\n"));
        sb.append("-------------------------共变化 ").append(list.size()).append("处，具体如下-------------------------").append("\n");
        for (int i = 0; i < list.size(); i++) {
            sb.append(String.format("【%s】%s", (i + 1), list.get(i))).append("\n");
        }
        return sb.toString();
    }

    /**
     * 比较表字段
     *
     * @author xuepeng
     * @date 2024/1/31 11:15
     */
    public static List<String> getDifferenceFieldList(String tableName, List<Column> fromColumn, List<Column> toColumn) {
        List<String> list = new ArrayList<String>();
        Map<String, String> toMap = toColumn.stream().collect(Collectors.toMap(Column::getColName, Column::getDataType));
        Map<String, String> fromMap = fromColumn.stream().collect(Collectors.toMap(Column::getColName, Column::getDataType));
        Set<String> toFiledSet = toMap.keySet();
        for (String filedName : toFiledSet) {
            String fromFileType = fromMap.get(filedName);
            // 如果目标文件表有该字段，源文件表没有该字段，则该字段已被删除，冗余
            if (fromFileType == null) {
                list.add(String.format("%s 目标表独有字段：%s", tableName, filedName));
                continue;
            }
            // 继续比较字段类型
            String toFileType = toMap.get(filedName);
            if (!fromFileType.equals(toFileType)) {
                list.add(String.format("%s 表字段变化：%s : %s（源） -> %s（目标）", tableName, filedName, fromFileType, toFileType));
            }
        }
        // 新增字段
        Set<String> fromFiledSet = fromMap.keySet();
        fromFiledSet.removeAll(toFiledSet);
        for (String fromFiledName : fromFiledSet) {
            list.add(String.format("%s 源表独有字段：%s : %s", tableName, fromFiledName, fromMap.get(fromFiledName)));
        }
        return list;
    }

    /**
     * 比较表索引
     *
     * @author xuepeng
     * @date 2024/1/31 11:17
     */
    public static List<String> getDifferenceIndexList(String tableName, List<Column> fromColumn, List<Column> toColumn) {
        List<String> list = new ArrayList<>();
        Map<String, String> toMap = toColumn.stream().collect(Collectors.toMap(Column::getColName, Column::getDataType));
        Map<String, String> fromMap = fromColumn.stream().collect(Collectors.toMap(Column::getColName, Column::getDataType));
        Set<String> toKeySet = toMap.keySet();
        for (String keyName : toKeySet) {
            String fromKeyType = fromMap.get(keyName);
            // 如果目标文件表有该索引，源文件表没有该索引，则该索引已被删除，冗余
            if (fromKeyType == null) {
                list.add(String.format("%s 目标表独有索引：%s: %s", tableName, keyName, toMap.get(keyName)));
                continue;
            }
            // 继续比较字段类型
            String toKeyType = toMap.get(keyName);
            if (!fromKeyType.equals(toKeyType)) {
                list.add(String.format("%s 表索引变化：%s : %s -> %s", tableName, keyName, fromKeyType, toKeyType));
            }
        }
        // 新增字段
        Set<String> fromKeySet = fromMap.keySet();
        fromKeySet.removeAll(toKeySet);
        for (String fromKeyName : fromKeySet) {
            list.add(String.format("%s 源表独有索引：%s : %s", tableName, fromKeyName, fromMap.get(fromKeyName)));
        }
        return list;
    }

    /**
     * 比较表数据
     *
     * @author xuepeng
     * @date 2024/1/31 11:16
     */
    public static List<String> getDifferenceContentList(String tableFrom, String tableTo, List<String> from, List<String> to) {
        List<String> list = new ArrayList<>();
        List<String> fromTemp = new ArrayList<>(from);
        List<String> toTemp = new ArrayList<>(to);
        fromTemp.removeAll(to);
        toTemp.removeAll(from);
        fromTemp.sort(null);
        toTemp.sort(null);
        for (String toContent : toTemp) {
            list.add(String.format("%s 目标表独有数据：%s ", tableFrom, toContent));
        }
        for (String fromContent : fromTemp) {
            list.add(String.format("%s 源表独有数据：%s ", tableTo, fromContent));
        }
        return list;
    }
}